#ifndef __CXXTEST_TESTRUNNER_H
#define __CXXTEST_TESTRUNNER_H

//
// TestRunner is the class that runs all the tests.
// To use it, create an object that implements the TestListener
// interface and call TestRunner::runAllTests( &myListener );
// 
// Modified by Penrillian, Smartphone Software Innovators 
// See http://www.penrillian.com
//
//Arguments names changed to avoid compiler warnings 
//Use of _TS_TRY and _TS_CATCH changed to reflect implementation using leave
 
#include <cxxtest/Runnable.h>
#include <cxxtest/TestListenerProxy.h>
#include <cxxtest/Descriptions.h>
#include <cxxtest/TestSuite.h>
#include "Logger.h"
#include "BuildTime.h"


const TInt KRunAllSuites = -1;

namespace CxxTest 
{
    class TestRunner : public TestListenerProxy
    {
    public:
        TestRunner( TestListener *l, MUiUpdater * aUI ) : TestListenerProxy( l->listener(),aUI ) {}

        static void runAllTests( TestListener *alistener, WorldDescription & world, MUiUpdater * aUI, TInt aSuite  )
        {
            runWorld( alistener->listener(), world, aUI, aSuite );
        }

        static void runWorld( TestListener *alistener, const WorldDescription &world, MUiUpdater * aUI, TInt aSuite  )
        {
            TestRunner( alistener->listener(),aUI ).runWorld( world, aSuite );
        }
    
    private:
        
        void runWorld( const WorldDescription &wd, TInt aSuite )
        {
            enterWorld( wd, aSuite );
            wd.setUp( this );
			if(aSuite != KRunAllSuites && aSuite < wd.numSuites())
			{
				checkAndRunSuite(wd, aSuite);
			}
			else
			{
				for ( TInt i = 0; i < wd.numSuites(); ++ i )
				{
					checkAndRunSuite(wd, i);
				}
			}
            wd.tearDown( this );
            leaveWorld( wd, aSuite );
        }

		void checkAndRunSuite(const WorldDescription &wd, TInt aSuite)
		{
			if ( wd.suiteDescription(aSuite).suite )
                    runSuite( wd.suiteDescription(aSuite) );
		}
    
        void runSuite( const SuiteDescription &sd )
        {
        	enterSuite( sd );
            sd.suite->setListener( this );
			iContinue = true;
            for ( unsigned i = 0; i < sd.numTests && iContinue; ++ i ) {
				TInt allocatedHeapCells = User::CountAllocCells();
				const char* testName = sd.tests[i].name;
				Logger::Log( "", testName );
				Logger::Log( "********** Test: %s **********", testName );
				sd.suite->setUp();
                runTest( sd.tests[i], sd );
                sd.suite->tearDown();
                TInt lostCells = User::CountAllocCells() - allocatedHeapCells;
				if (lostCells != 0 && lostCells != sd.suite->iMemoryLeakCells )
				{
					failedTest(sd.tests[i].suite, testName, lostCells, "Memory Leak");
				}
				testCompleted();
            }
            leaveSuite( sd );
        }

        void runTest( const TestDescription &td, const SuiteDescription &sd )
        {
            enterTest( td, sd );
			TRAPD(err, td.test->run());

			//td.test->run();
			
			if (err == -1003)  // EPOC Exit application.
			{
				iContinue = false;
			}
			else if(err != 0)
			{ 
				TBuf8<30> result;
				result.Format( _L8( "Left with code %d" ), err );
				result.ZeroTerminate();
				failedTest(td.suite, td.name,td.line,(const char*)result.Ptr());
			}

            leaveTest( td, sd); 
        }
		bool iContinue;
   
    };
}


#endif // __CXXTEST_TESTRUNNER_H
